package com.linq.cool.system.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.linq.cool.api.domain.SysFile;
import com.linq.cool.api.domain.SysRole;
import com.linq.cool.api.domain.SysUser;
import com.linq.cool.api.dto.SysUserLastLoginDTO;
import com.linq.cool.api.feign.RemoteFileService;
import com.linq.cool.api.vo.LoginUser;
import com.linq.cool.api.vo.SysUserVO;
import com.linq.cool.common.constants.UserConstants;
import com.linq.cool.common.core.domain.BaseController;
import com.linq.cool.common.core.domain.PageVO;
import com.linq.cool.common.core.domain.Result;
import com.linq.cool.common.core.utils.*;
import com.linq.cool.common.log.annotation.Log;
import com.linq.cool.common.log.enums.BusinessType;
import com.linq.cool.common.security.annotation.PreAuthorize;
import com.linq.cool.common.security.service.SysTokenService;
import com.linq.cool.system.dto.*;
import com.linq.cool.system.service.SysPermissionService;
import com.linq.cool.system.service.SysPostService;
import com.linq.cool.system.service.SysRoleService;
import com.linq.cool.system.service.SysUserService;
import com.linq.cool.system.vo.SysUserInfoVO;
import com.linq.cool.system.vo.SysUserProfileVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: yqlin
 * @Date: 2020/12/31 10:51
 * @Description:
 * @Version: 1.0.0
 */
@RestController
@RequestMapping("user")
@Slf4j
public class SysUserController extends BaseController {
    @Value("${test}")
    private String test;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysPermissionService sysPermissionService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysPostService sysPostService;
    @Autowired
    private SysTokenService sysTokenService;
    @Autowired
    private RemoteFileService remoteFileService;

    @GetMapping("test")
    public Result<Object> test() {
        Map<String, Object> map = new HashMap<>(2);
        map.put("test", test);
        map.put("not.null", MessageUtils.message("not.null"));
        return Result.ok(map);
    }

    /**
     * 条件分页获取用户列表
     *
     * @param dto 条件信息
     *
     * @return 分页数据集合
     */
    @PreAuthorize(hasPerm = "sys:user:list")
    @GetMapping("list")
    public Result<?> list(SysUserQueryDTO dto) {
        log.info("SysUserQueryDTO: {}", dto);
        IPage<SysUserVO> page = sysUserService.listByPage(dto.getPage(), dto);
        return Result.ok(new PageVO().setTotal(page.getTotal()).setRecords(page.getRecords()));
    }

    /**
     * 根据用户名获取当前用户信息
     *
     * @param username 用户名
     *
     * @return LoginUser
     */
    @GetMapping("info/{username}")
    public Result<LoginUser> getUserInfo(@PathVariable("username") String username) {
        SysUserVO sysUserVO = sysUserService.getByUsername(username);
        if (StringUtils.isNull(sysUserVO)) {
            return Result.fail("用户名不存在");
        }
        // 角色权限集合
        Set<String> roleSet = sysPermissionService.listRolePermissionByUserId(sysUserVO.getId());
        // 菜单权限集合
        Set<String> menuSet = sysPermissionService.listMenuPermissionByUserId(sysUserVO.getId());
        return Result.ok(new LoginUser().setSysUserVO(sysUserVO).setRoles(roleSet).setPermissions(menuSet));
    }

    /**
     * 根据token获取用户信息
     *
     * @return 用户详细信息
     */
    @GetMapping("getInfo")
    public Result<?> getInfo() {
        Long userId = SecurityUtils.getUserId();
        Set<String> roleSet = sysPermissionService.listRolePermissionByUserId(userId);
        Set<String> menuSet = sysPermissionService.listMenuPermissionByUserId(userId);
        return Result.ok(new SysUserInfoVO().setUser(sysUserService.getById(userId)).setRoles(roleSet).setPermissions(menuSet));
    }

    /**
     * 根据用户编号获取详细信息
     */
    @PreAuthorize(hasPerm = "sys:user:query")
    @GetMapping(value = {"", "{userId}"})
    public Result<?> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
        List<SysRole> roles = sysRoleService.list(new LambdaQueryWrapper<SysRole>()
                                                          .eq(SysRole::getIsDeleted, UserConstants.StateEnum.STATUS_NORMAL.getCode())
                                                          .orderByAsc(SysRole::getSort)
        );
        Map<String, Object> map = new HashMap<>(8);
        map.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        map.put("posts", sysPostService.list());
        if (StringUtils.isNotNull(userId)) {
            map.put("userInfo", sysUserService.getById(userId).setPassword(null));
            map.put("postIds", sysPostService.listByUserId(userId));
            map.put("roleIds", sysRoleService.listByUserId(userId));
        }
        return Result.ok(map);
    }

    /**
     * 新增用户
     */
    @Log(moduleTitle = "用户管理", businessType = BusinessType.INSERT)
    @PreAuthorize(hasPerm = "sys:user:add")
    @PostMapping
    public Result<?> add(@Validated @RequestBody SysUserAddDTO dto) {
        if (!RegexUtils.checkMobile(dto.getPhone())) {
            return Result.fail("手机号不合法");
        }
        log.info("SysUserAddDTO:{}", dto);
        return this.toResult(sysUserService.saveUser(dto));
    }

    /**
     * 修改用户
     */
    @Log(moduleTitle = "用户管理", businessType = BusinessType.UPDATE)
    @PreAuthorize(hasPerm = "sys:user:edit")
    @PutMapping
    public Result<?> edit(@Validated @RequestBody SysUserUpdateDTO dto) {
        return this.toResult(sysUserService.updateUser(dto));
    }

    /**
     * 删除用户
     */
    @Log(moduleTitle = "用户管理", businessType = BusinessType.DELETE)
    @PreAuthorize(hasPerm = "sys:user:remove")
    @DeleteMapping("{userIds}")
    public Result<?> remove(@PathVariable List<Long> userIds) {
        return this.toResult(sysUserService.deleteByIds(userIds));
    }

    /**
     * 重置密码
     */
    @Log(moduleTitle = "用户管理", businessType = BusinessType.UPDATE)
    @PreAuthorize(hasPerm = "sys:user:edit")
    @PutMapping("/resetPwd")
    public Result<?> resetPwd(@Validated @RequestBody SysUserResetPasswordDTO dto) {
        SysUser user = new SysUser().setId(dto.getId()).setPassword(dto.getPassword());
        sysUserService.checkAllowed(user);
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        user.setModifier(SecurityUtils.getUserId()).setGmtModified(new Date());
        return this.toResult(sysUserService.updateById(user));
    }

    /**
     * 状态修改
     */
    @Log(moduleTitle = "用户管理", businessType = BusinessType.UPDATE)
    @PreAuthorize(hasPerm = "sys:user:edit")
    @PutMapping("/changeStatus/{userId}/{status}")
    public Result<?> changeStatus(@PathVariable("userId") Long userId, @PathVariable("status") Integer status) {
        SysUser user = new SysUser();
        user.setId(userId).setStatus(status);
        sysUserService.checkAllowed(user);
        user.setModifier(SecurityUtils.getUserId()).setGmtModified(new Date());
        return this.toResult(sysUserService.updateById(user));
    }

    /**
     * 更新登录信息
     *
     * @param dto
     *
     * @return
     */
    @PutMapping("/updateLoginInfo")
    public Result<?> updateLoginInfo(@RequestBody SysUserLastLoginDTO dto) {
        SysUser user = new SysUser();
        BeanUtils.copyProperties(dto, user);
        log.info("updateLoginInfo:{}", user);
        return Result.ok(sysUserService.updateById(user));
    }


    /**
     * 获取个人信息
     *
     * @return
     */
    @GetMapping("profile")
    public Result<?> profile() {
        Long userId = SecurityUtils.getUserId();
        SysUser user = sysUserService.getById(userId);
        String roleGroup = sysUserService.getRoleGropByUserId(userId);
        String postGroup = sysUserService.getPostGropByUserId(userId);
        return Result.ok(new SysUserProfileVO().setUser(user).setRoleGroup(roleGroup).setPostGroup(postGroup));
    }

    @Log(moduleTitle = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping("profile")
    public Result<?> updateProfile(@RequestBody SysUserUpdateProfileDTO dto) {
        SysUser user = new SysUser();
        BeanUtils.copyProperties(dto, user);
        user.setGmtModified(new Date())
                .setModifier(SecurityUtils.getUserId());
        if (sysUserService.updateById(user)) {
            LoginUser loginUser = sysTokenService.getLoginUser();
            // 更新缓存
            loginUser.getSysUserVO()
                    .setNickname(user.getNickname())
                    .setPhone(user.getPhone())
                    .setEmail(user.getEmail())
                    .setGender(user.getGender());
            sysTokenService.setLoginUser(loginUser);
            return Result.ok("更新成功");
        }
        return Result.fail("修改个人信息异常，请联系管理员");
    }

    /**
     * 重置密码
     */
    @Log(moduleTitle = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping("profile/updatePwd")
    public Result<?> updatePwd(String oldPassword, String newPassword) {
        SysUser user = sysUserService.getById(SecurityUtils.getUserId());
        String prePasswrd = user.getPassword();
        if (!SecurityUtils.matchesPassword(oldPassword, prePasswrd)) {
            return Result.fail("修改密码失败，旧密码错误");
        }
        if (SecurityUtils.matchesPassword(newPassword, prePasswrd)) {
            return Result.fail("新密码不能与旧密码相同");
        }
        // 更新密码
        user.setPassword(SecurityUtils.encryptPassword(newPassword));
        if (sysUserService.updateById(user)) {
            LoginUser loginUser = sysTokenService.getLoginUser();
            // 更新缓存
            loginUser.getSysUserVO().setPassword(user.getPassword());
            sysTokenService.setLoginUser(loginUser);
            return Result.ok("更新成功");
        }
        return Result.fail("修改密码异常，请联系管理员");
    }

    @Log(moduleTitle = "用户头像", businessType = BusinessType.UPDATE)
    @PostMapping("profile/avatar")
    public Result<?> avatar(@RequestParam("file") MultipartFile file) throws IOException {
        if (!file.isEmpty()) {
            log.info("上传文件stream:{}", file.getInputStream());
            Result<SysFile> fileResult = remoteFileService.upload(file);
            log.info("返回结果:{}", fileResult);
            if (fileResult.getData() == null) {
                return Result.fail("文件上传失败 , 请联系管理员");
            }
            String url = fileResult.getData().getUrl();
            LoginUser loginUser = sysTokenService.getLoginUser(ServletUtils.getRequest());
            SysUser user = sysUserService.getById(loginUser.getUserId());
            user.setAvatar(url);
            if (sysUserService.updateById(user)) {
                loginUser.getSysUserVO().setAvatar(user.getAvatar());
                sysTokenService.setLoginUser(loginUser);
                return Result.ok("修改成功");
            }
        }
        return Result.fail("上传图片异常，请联系管理员");
    }

    @PostMapping("testFile")
    public Result<?> testFile(@RequestParam("file") MultipartFile file) {
        return remoteFileService.upload(file);
    }
}
